package com.xc.ezplan.admin.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xc.ezplan.admin.entity.AdminJob;
import com.xc.ezplan.admin.entity.AdminRole;
import com.xc.ezplan.admin.entity.AdminUser;
import com.xc.ezplan.admin.entity.AdminUsersJobs;
import com.xc.ezplan.admin.entity.AdminUsersRoles;
import com.xc.ezplan.admin.mapper.AdminDeptMapper;
import com.xc.ezplan.admin.mapper.AdminJobMapper;
import com.xc.ezplan.admin.mapper.AdminRoleMapper;
import com.xc.ezplan.admin.mapper.AdminUserMapper;
import com.xc.ezplan.admin.mapper.AdminUsersJobsMapper;
import com.xc.ezplan.admin.mapper.AdminUsersRolesMapper;
import com.xc.ezplan.admin.service.AdminPurviewService;
import com.xc.ezplan.admin.service.AdminUserService;
import com.xc.ezplan.admin.vo.AdminUserVo;
import com.xc.ezplan.cache.constants.RedisKey;
import com.xc.ezplan.cache.utils.CacheUtil;
import com.xc.ezplan.cache.utils.RedisUtils;
import com.xc.ezplan.core.base.SearchCondition;
import com.xc.ezplan.core.dto.AdminUserDTO;
import com.xc.ezplan.core.exception.EntityExistException;
import com.xc.ezplan.core.utils.FileUtil;
import com.xc.ezplan.core.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author lixingchen
 * @date 2022/11/19
 * @description 后台角色实现类
 */
@Service
@Primary
@RequiredArgsConstructor
@CacheConfig(cacheNames = "user")
public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdminUser> implements AdminUserService {

	private final AdminUserMapper adminUserMapper;

	private final AdminRoleMapper adminRoleMapper;

	private final AdminJobMapper adminJobMapper;

	private final AdminUsersRolesMapper adminUsersRolesMapper;

	private final AdminUsersJobsMapper adminUsersJobsMapper;

	private final AdminDeptMapper adminDeptMapper;

	private final RedisUtils redisUtils;

	private final AdminPurviewService adminPurviewService;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Object createUser(AdminUserVo adminUserVo) {
		// 校验 用户名 邮箱 手机号 不能重复
		if (adminUserMapper.selectCount(
				new QueryWrapper<AdminUser>().lambda().eq(AdminUser::getUsername, adminUserVo.getUsername())) > 0) {
			throw new EntityExistException(AdminUser.class, "username", adminUserVo.getUsername());
		}
		if (adminUserMapper.selectCount(
				new QueryWrapper<AdminUser>().lambda().eq(AdminUser::getEmail, adminUserVo.getEmail())) > 0) {
			throw new EntityExistException(AdminUser.class, "email", adminUserVo.getEmail());
		}
		if (adminUserMapper.selectCount(
				new QueryWrapper<AdminUser>().lambda().eq(AdminUser::getPhone, adminUserVo.getPhone())) > 0) {
			throw new EntityExistException(AdminUser.class, "phone", adminUserVo.getPhone());
		}
		AdminUser adminUser = new AdminUser();
		// 默认密码123456 MD5加密存储
		adminUser.setPassword(SecureUtil.md5("123456"));
		BeanUtils.copyProperties(adminUserVo, adminUser);
		adminUserMapper.insert(adminUser);
		addRolesAndJobsRelation(adminUserVo, adminUser.getId());
		return null;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateUser(AdminUserVo adminUserVo) {
		Long userId = adminUserVo.getId();
		// 校验 用户名 邮箱 手机号 不能重复
		if (adminUserMapper.selectCount(new QueryWrapper<AdminUser>().lambda()
				.eq(AdminUser::getUsername, adminUserVo.getUsername()).ne(AdminUser::getId, userId)) > 0) {
			throw new EntityExistException(AdminUser.class, "username", adminUserVo.getUsername());
		}
		if (adminUserMapper.selectCount(new QueryWrapper<AdminUser>().lambda()
				.eq(AdminUser::getEmail, adminUserVo.getEmail()).ne(AdminUser::getId, userId)) > 0) {
			throw new EntityExistException(AdminUser.class, "email", adminUserVo.getEmail());
		}
		if (adminUserMapper.selectCount(new QueryWrapper<AdminUser>().lambda()
				.eq(AdminUser::getPhone, adminUserVo.getPhone()).ne(AdminUser::getId, userId)) > 0) {
			throw new EntityExistException(AdminUser.class, "phone", adminUserVo.getPhone());
		}
		// 添加用户信息
		AdminUser adminUser = new AdminUser();
		BeanUtils.copyProperties(adminUserVo, adminUser);
		adminUserMapper.update(adminUser, new UpdateWrapper<AdminUser>().lambda()
				.set(AdminUser::getUsername, adminUser.getUsername()).set(AdminUser::getEmail, adminUser.getEmail())
				.set(AdminUser::getEnabled, adminUser.getEnabled()).set(AdminUser::getPhone, adminUser.getPhone())
				.set(AdminUser::getNickName, adminUser.getNickName()).set(AdminUser::getGender, adminUser.getGender())
				.eq(AdminUser::getId, userId));
		// 删除用户与角色/岗位关联信息
		deleteRolesAndJobsRelation(userId);
		// 添加用户与角色/岗位关联信息
		addRolesAndJobsRelation(adminUserVo, userId);
		// 删除与该用户相关的 用户/角色/权限 缓存
		CacheUtil.deleteCache(RedisKey.USER_ID, adminUserVo.getId());
		CacheUtil.deleteCache(RedisKey.PURVIEW_PERMISSION_ID, adminUserVo.getId());
		CacheUtil.deleteCache(RedisKey.PURVIEW_ROLE_ID, adminUserVo.getId());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteUser(List<Long> ids) {
		for (Long userId : ids) {
			adminUserMapper.deleteById(userId);
			// 删除用户与角色/岗位关联信息
			deleteRolesAndJobsRelation(userId);
		}
		CacheUtil.deleteCache(RedisKey.USER_ID, ids);
		CacheUtil.deleteCache(RedisKey.PURVIEW_PERMISSION_ID, ids);
		CacheUtil.deleteCache(RedisKey.PURVIEW_ROLE_ID, ids);
	}

	@Override
	@Cacheable(key = "'id:' + #p0")
	public Object queryUser(Long userId) {
		AdminUserVo adminUserVo = new AdminUserVo();
		if (userId != null) {
			AdminUser adminUser = adminUserMapper.selectById(userId);
			BeanUtils.copyProperties(adminUser, adminUserVo);
			List<Long> roleIds = adminUsersRolesMapper
					.selectList(new QueryWrapper<AdminUsersRoles>().lambda().eq(AdminUsersRoles::getUserId, userId))
					.stream().map(AdminUsersRoles::getRoleId).collect(Collectors.toList());
			List<Long> jobIds = adminUsersJobsMapper
					.selectList(new QueryWrapper<AdminUsersJobs>().lambda().eq(AdminUsersJobs::getUserId, userId))
					.stream().map(AdminUsersJobs::getJobId).collect(Collectors.toList());
			adminUserVo.setRoleIds(roleIds);
			adminUserVo.setJobIds(jobIds);
		}
		adminUserVo.setRoleList(adminRoleMapper.selectList(null));
		adminUserVo.setJobList(adminJobMapper.selectList(null));
		adminUserVo.setDeptList(adminDeptMapper.selectList(null));
		return adminUserVo;
	}

	@Override
	public Object pageQueryUser(SearchCondition searchCondition, Page<AdminUser> page) {
		List<Date> createTime = searchCondition.getCreateTime();
		LambdaQueryWrapper<AdminUser> queryWrapper = new QueryWrapper<AdminUser>().lambda()
				.like(StringUtils.isNotBlank(searchCondition.getKeyWord()), AdminUser::getUsername,
						searchCondition.getKeyWord())
				.eq(searchCondition.getDeptId() != null, AdminUser::getDeptId, searchCondition.getDeptId());
		if (!CollectionUtils.isEmpty(createTime) && createTime.size() == 2) {
			queryWrapper.between(AdminUser::getCreateTime, createTime.get(0), createTime.get(1));
		}
		return adminUserMapper.selectPage(page, queryWrapper);

	}

	@Override
	public AdminUserDTO queryUserByUserName(String username) {
		AdminUser adminUser = adminUserMapper
				.selectOne(new QueryWrapper<AdminUser>().lambda().eq(AdminUser::getUsername, username));
		AdminUserDTO adminUserDTO = new AdminUserDTO();
		BeanUtils.copyProperties(adminUser, adminUserDTO);
		return adminUserDTO;
	}

	@Override
	public Map<String, Object> queryUserInfo() {
		long userId = StpUtil.getLoginIdAsLong();
		AdminUserDTO userInfo = (AdminUserDTO) StpUtil.getSession().get("userInfo");
		Map<String, Object> resultMap = new HashMap<>(4);
		resultMap.put("name", userInfo.getUsername());
		resultMap.put("phone", userInfo.getPhone());
		resultMap.put("email", userInfo.getEmail());
		resultMap.put("avatar", userInfo.getAvatarPath());
		resultMap.put("introduction", "");
		resultMap.put("permissions", adminPurviewService.getRolesByUser(userId));
		resultMap.put("roles", adminPurviewService.getPermissionsByUser(userId));
		return resultMap;
	}

	@Override
	public Object changeEnabled(Long userId, Boolean enabled) {
		AdminUser adminUser = new AdminUser();
		adminUser.setId(userId);
		adminUser.setEnabled(enabled);
		adminUserMapper.updateById(adminUser);
		return null;
	}

	@Override
	public void updateUserPass(JSONObject jsonObject) {
		String password = (String) jsonObject.get("password");
		List<Long> userIds = (List<Long>) jsonObject.get("userIds");
		AdminUser adminUser = new AdminUser();
		adminUser.setPassword(password);
		adminUserMapper.update(adminUser, new UpdateWrapper<AdminUser>().lambda().in(AdminUser::getId, userIds));
	}

	@Override
	public Object updateUserAvatar() {
		return null;
	}

	@Override
	public Object updateUserEmail() {
		return null;
	}

	@Override
	public Object centerUser() {
		return null;
	}

	@Override
	public void exportUser(List<Long> userIds) throws IOException {
		List<Map<String, Object>> list = new ArrayList<>();
		List<AdminUser> adminUsers = adminUserMapper
				.selectList(new QueryWrapper<AdminUser>().lambda().in(AdminUser::getId, userIds));
		for (AdminUser adminUser : adminUsers) {
			List<String> roles = adminRoleMapper
					.selectList(new QueryWrapper<AdminRole>().lambda().in(AdminRole::getId,
							adminUsersRolesMapper
									.selectList(new QueryWrapper<AdminUsersRoles>().lambda()
											.ne(AdminUsersRoles::getUserId, adminUser.getId()))
									.stream().map(AdminUsersRoles::getRoleId).collect(Collectors.toList())))
					.stream().map(AdminRole::getName).collect(Collectors.toList());
			Map<String, Object> map = new LinkedHashMap<>();
			map.put("用户名", adminUser.getUsername());
			map.put("角色", roles);
			map.put("部门", adminDeptMapper.selectById(adminUser.getDeptId()).getName());
			List<String> jobs = adminJobMapper
					.selectList(new QueryWrapper<AdminJob>().lambda().in(AdminJob::getId,
							adminUsersJobsMapper
									.selectList(new QueryWrapper<AdminUsersJobs>().lambda()
											.ne(AdminUsersJobs::getUserId, adminUser.getId()))
									.stream().map(AdminUsersJobs::getJobId).collect(Collectors.toList())))
					.stream().map(AdminJob::getName).collect(Collectors.toList());
			map.put("岗位", jobs);
			map.put("邮箱", adminUser.getEmail());
			map.put("状态", adminUser.getEnabled().equals(1L) ? "启用" : "禁用");
			map.put("手机号码", adminUser.getPhone());
			map.put("修改密码的时间", adminUser.getPwdResetTime());
			map.put("创建日期", adminUser.getCreateTime());
			list.add(map);
		}
		FileUtil.downloadExcel(list);
	}

	/**
	 * @description : 添加用户与角色/岗位关联信息
	 * @param adminUserVo: 用户vo
	 * @param userId:      用户id
	 */
	private void addRolesAndJobsRelation(AdminUserVo adminUserVo, long userId) {
		// 增加用户角色关联
		List<Long> roles = adminUserVo.getRoleIds();
		for (Long roleId : roles) {
			AdminUsersRoles adminUsersRoles = new AdminUsersRoles();
			adminUsersRoles.setUserId(userId);
			adminUsersRoles.setRoleId(roleId);
			adminUsersRolesMapper.insert(adminUsersRoles);
		}
		// 增加用户岗位关联
		List<Long> jobs = adminUserVo.getJobIds();
		for (Long jobId : jobs) {
			AdminUsersJobs adminUsersJobs = new AdminUsersJobs();
			adminUsersJobs.setUserId(userId);
			adminUsersJobs.setJobId(jobId);
			adminUsersJobsMapper.insert(adminUsersJobs);
		}
	}

	/**
	 * @description : 删除用户与角色/岗位关联信息
	 * @param userId: 用户id
	 */
	private void deleteRolesAndJobsRelation(Long userId) {
		// 删除用户角色关联
		adminUsersRolesMapper
				.delete(new QueryWrapper<AdminUsersRoles>().lambda().eq(AdminUsersRoles::getUserId, userId));
		// 删除用户岗位关联
		adminUsersJobsMapper.delete(new QueryWrapper<AdminUsersJobs>().lambda().eq(AdminUsersJobs::getUserId, userId));
	}

}
